package com.richpencil.modules.weixin.service;

import com.alibaba.fastjson.JSON;
import com.richpencil.modules.weixin.domain.RedPackObject;
import com.richpencil.modules.weixin.domain.UnifiedOrderObject;
import com.richpencil.utils.HttpHelper;
import com.richpencil.utils.StringHelper;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.DigestException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;

public class WechatHelper {

    public static RedPackObject getRedPackReturnCode(Map<String, String> map) {

        RedPackObject robject=new RedPackObject(map);
        return robject;
    }

    public static UnifiedOrderObject getRequestReturnCode(HttpServletRequest request) throws IOException
    {
        InputStream inStream = request.getInputStream();
        ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = inStream.read(buffer)) != -1) {
            outSteam.write(buffer, 0, len);
        }
        outSteam.close();
        inStream.close();
        String result = new String(outSteam.toByteArray(), "utf-8");// 获取微信调用我们notify_url的返回信息
        Map<String, Object> map = StringHelper.getXMLToMap(result);
        UnifiedOrderObject object=new UnifiedOrderObject(map);
        return object;
    }


    //付款成功，返回给微信服务器的消息
    public static String setWechatPayReturnXML(String return_code, String return_msg) {
        return "<xml><return_code><![CDATA[" + return_code
                + "]]></return_code><return_msg><![CDATA[" + return_msg
                + "]]></return_msg></xml>";
    }

    /**
     * 微信获取accesstoken
     *
     * @param 	appid
     * @param 	secret
     * @return 	accesstoken
     */
    public static String wxGetAccessToken(String appid,String secret){
        String jsonobject = HttpHelper.sendGet("https://api.weixin.qq.com/cgi-bin/token",
                "grant_type=client_credential&appid="+appid+"&secret="+secret);
        Map maps = (Map) JSON.parse(jsonobject);
        String accesstoken = maps.get("access_token").toString();
        return accesstoken;
    }



    //获取token
    public static final String URL_access_token = "https://api.weixin.qq.com/cgi-bin/token";
    //统一下单
    public static final String URL_unifiedorder = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    //oauth2请求授权
    public static final String URL_oauth2 = "https://open.weixin.qq.com/connect/oauth2/authorize";
    //oauth2获取access_token
    public static final String URL_oauth2token = "https://api.weixin.qq.com/sns/oauth2/access_token";
    //根据token获取ticket
    public static final String URL_getticket = "https://api.weixin.qq.com/cgi-bin/ticket/getticket";
    //拉取用户信息(需scope为 snsapi_userinfo)
    public static final String URL_userinfo = "https://api.weixin.qq.com/sns/userinfo";




    //微信开放平台审核通过的应用APPID
    public static final String appid = "wxce96b9dd56cd24e7";
    //应用密钥
    public static final String appsecret = "16d112c45a61b6a4c6719473ad436c22";
    //微信支付分配的商户号
    public static final String mch_id = "1484459972";
    //终端设备号(门店号或收银设备ID)，默认请传"WEB"
    public static final String device_info = "WEB";
    //支付类型
    public static final String trade_type = "JSAPI";
    //指定支付方式  no_credit--指定不能使用信用卡支付
    public static final String limit_pay = "limit_pay";
    // 字符编码格式 目前支持utf-8
    public static final String input_charset = "utf-8";
    /**
     * 弹出授权页面，可通过openid拿到昵称、性别、所在地。并且，即使在未关注的情况下，只要用户授权，也能获取其信息
     */
    public static final String scope_snsapi_userinfo = "snsapi_userinfo";
    /**
     * 不弹出授权页面，直接跳转，只能获取用户openid
     */
    public static final String scope_snsapi_base = "snsapi_base";

    private static Map<String,Object> accessTokenCache = new HashMap<String,Object>();
    private static Map<String,Object> jsapiTicketCache = new HashMap<String,Object>();
    public static String getAccessToken(){
        String access_token = "";
        String tokenKey = "tokenKey";
        String tokenTimeKey = "tokenTimeKey";
        String appId = appid;
        String appSecret = appsecret;
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
        try{
            if(accessTokenCache.containsKey(tokenKey)){
                Date cacheTime = (Date)accessTokenCache.get(tokenTimeKey);//获取token时间
                long currentTime = System.currentTimeMillis();//系统当前实际时间
                long cacheCreateTime = cacheTime.getTime();//token创建时间
                long diffTime = currentTime - cacheCreateTime;//token持续时间
                int cacheMinutes = 5;//分钟
                long cacheTimeRange = cacheMinutes * 60  * 1000;
                if (diffTime < cacheTimeRange ){//token持续7分钟以内，使用原token
                    access_token = (String)accessTokenCache.get(tokenKey);
                }
            }
            if(access_token.equals("")){
                Map map = new HashMap();
                map.put("grant_type", "client_credential");
                map.put("appid", appId);
                map.put("secret", appSecret);
                String str_Token = HttpHelper.sendPost(URL_access_token, map);
                Map map_Token = StringHelper.jsonStr2Map(str_Token);
                access_token = map_Token.get("access_token").toString();
                accessTokenCache.put(tokenKey, access_token);
                accessTokenCache.put(tokenTimeKey, new Date());
            }
        }
        catch(Exception ex){
            access_token = "";
        }
        return access_token;
    }
    public static String getJsapiTicket(){
        String access_token = getAccessToken();
        String jsapi_ticket = "";
        String ticketKey = "ticketKey";
        String ticketTimeKey = "ticketTimeKey";
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
        try{
            if(jsapiTicketCache.containsKey(ticketKey)){
                Date cacheTime = (Date)jsapiTicketCache.get(ticketTimeKey);//获取token时间
                long currentTime = System.currentTimeMillis();//系统当前实际时间
                long cacheCreateTime = cacheTime.getTime();//token创建时间
                long diffTime = currentTime - cacheCreateTime;//token持续时间
                int cacheMinutes = 5;//分钟
                long cacheTimeRange = cacheMinutes * 60  * 1000;
                if (diffTime < cacheTimeRange ){//token持续7分钟以内，使用原token
                    jsapi_ticket = jsapiTicketCache.get(ticketKey).toString();
                }
            }
            if(jsapi_ticket.equals("")){
                Map<String, String> map = new HashMap<>();
                map.put("access_token", access_token);
                map.put("type", "jsapi");
                String str_Token = HttpHelper.sendPost(URL_getticket, map);
                Map map_Ticket = StringHelper.jsonStr2Map(str_Token);
                jsapi_ticket = map_Ticket.get("ticket").toString();
                jsapiTicketCache.put(ticketKey, jsapi_ticket);
                jsapiTicketCache.put(ticketTimeKey, new Date());
            }
        }
        catch(Exception ex){
            jsapi_ticket = "";
        }
        return jsapi_ticket;
    }

    /**
     * SHA1 安全加密算法
     * @param maps 参数key-value map集合
     * @return
     * @throws DigestException
     */
    public static String SHA1(Map<String, Object> maps) throws DigestException {
        //获取信息摘要 - 参数字典排序后字符串
        String decrypt = getOrderByLexicographic(maps);
        try {
            //指定sha1算法
            MessageDigest digest = MessageDigest.getInstance("SHA-1");
            digest.update(decrypt.getBytes());
            //获取字节数组
            byte messageDigest[] = digest.digest();
            // Create Hex String
            StringBuffer hexString = new StringBuffer();
            // 字节数组转换为 十六进制 数
            for (int i = 0; i < messageDigest.length; i++) {
                String shaHex = Integer.toHexString(messageDigest[i] & 0xFF);
                if (shaHex.length() < 2) {
                    hexString.append(0);
                }
                hexString.append(shaHex);
            }
            return hexString.toString().toUpperCase();

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            throw new DigestException("签名错误！");
        }
    }
    /**
     * 获取参数的字典排序
     * @param maps 参数key-value map集合
     * @return String 排序后的字符串
     */
    private static String getOrderByLexicographic(Map<String,Object> maps){
        System.out.println(splitParams(lexicographicOrder(getParamsName(maps)),maps));
        //jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW&timestamp=1414587457&url=http://mp.weixin.qq.com?params=value
        //jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW&timestamp=1414587457&url=http://mp.weixin.qq.com?params=value
        return splitParams(lexicographicOrder(getParamsName(maps)),maps);
    }
    /**
     * 获取参数名称 key
     * @param maps 参数key-value map集合
     * @return
     */
    private static List<String> getParamsName(Map<String,Object> maps){
        List<String> paramNames = new ArrayList<String>();
        for(Map.Entry<String,Object> entry : maps.entrySet()){
            paramNames.add(entry.getKey());
        }
        return paramNames;
    }
    /**
     * 参数名称按字典排序
     * @param paramNames 参数名称List集合
     * @return 排序后的参数名称List集合
     */
    private static List<String> lexicographicOrder(List<String> paramNames){
        Collections.sort(paramNames);
        return paramNames;
    }
    /**
     * 拼接排序好的参数名称和参数值
     * @param paramNames 排序后的参数名称集合
     * @param maps 参数key-value map集合
     * @return String 拼接后的字符串
     */
    private static String splitParams(List<String> paramNames,Map<String,Object> maps){
        StringBuilder paramStr = new StringBuilder();
        for(String paramName : paramNames){
            paramStr.append(paramName);
            for(Map.Entry<String,Object> entry : maps.entrySet()){
                if(paramName.equals(entry.getKey())){
                    paramStr.append("="+String.valueOf(entry.getValue())+"&");
                }
            }
        }
        paramStr.deleteCharAt(paramStr.length()-1);
        return paramStr.toString();
    }
}